/**
 * Request 模式代理工具函数
 * 复用 Playwright 模式的代理选择逻辑
 */

import { getConfig } from '../config/index'
import { ProxyLease } from '../shared/proxy-lease'

/**
 * 代理选择结果（包含代理池信息）
 */
export interface ProxySelectionResult {
  server: string
  username?: string
  password?: string
  providerId?: string
  providerLabel?: string
  poolSize?: number
  filteredSize?: number
  candidateSize?: number
  // 是否为本次选择成功加租约（true 则调用方应在流程结束后 release）
  leased?: boolean
}

/**
 * 为会话选择代理（复用 booking-browser-manager 的逻辑）
 * @returns 代理信息（包含代理池信息）或 null
 */
export function selectProxyForRequestSession(): ProxySelectionResult | null {
  try {
    const config = getConfig()
    const proxy = (config && config.proxy) ? config.proxy : null
    if (!proxy || proxy.enabled !== true)
      return null

    const blacklist: Array<{ server: string, until?: number }> = Array.isArray(proxy.temp_blacklist) ? proxy.temp_blacklist : []
    const now = Date.now()

    const candidates: Array<{ host: string, port: string, username?: string, password?: string, serverStr: string, providerId?: string, providerLabel?: string }> = []

    function pushEntry(entry: string, fallbackAuth?: { username: string, password: string }, proto?: string, providerId?: string, providerLabel?: string) {
      const parts = String(entry || '').split(':')
      if (parts.length >= 4) {
        const host = parts[0]
        const port = parts[1]
        const username = parts[2]
        const password = parts.slice(3).join(':')
        const serverStr = `${(proto || 'http')}://${host}:${port}`
        candidates.push({ host, port, username, password, serverStr, providerId, providerLabel })
      }
      else if (parts.length >= 2) {
        const host = parts[0]
        const port = parts[1]
        const username = fallbackAuth?.username
        const password = fallbackAuth?.password
        const serverStr = `${(proto || 'http')}://${host}:${port}`
        candidates.push({ host, port, username, password, serverStr, providerId, providerLabel })
      }
    }

    const providers: any[] = Array.isArray(proxy.providers) ? proxy.providers : []
    let totalPoolSize = 0
    for (const p of providers) {
      if (!p || p.enabled === false)
        continue
      const pProto = p.protocol || 'http'
      const pAuth = (p.auth && p.auth.username) ? p.auth : undefined
      const pool: string[] = Array.isArray(p.pool) ? p.pool : []
      totalPoolSize += pool.length
      const providerId = p.id || 'unknown'
      const providerLabel = p.label || p.name || providerId
      for (const e of pool)
        pushEntry(e, pAuth, pProto, providerId, providerLabel)
    }

    if (candidates.length === 0)
      return null

    const filtered = candidates.filter((c) => {
      for (const b of blacklist) {
        if (!b || (b.until && b.until <= now))
          continue
        if (b.server === c.serverStr)
          return false
        if (b.server && b.server.endsWith(`${c.host}:${c.port}`))
          return false
      }
      return true
    })

    const pool = filtered.length > 0 ? filtered : candidates

    // 优先选择未被租约占用的 server（仅对多候选有效）；sticky 按 server+username 视为独立会话
    const leaseTtlSec = Math.max(30, Number((config?.proxy as any)?.lease_ttl_seconds || 300))
    const preferList = [...pool]
    let picked: typeof pool[number] | null = null
    let leased = false
    for (let i = 0; i < preferList.length; i++) {
      const idx = (Math.floor(Math.random() * preferList.length) + i) % preferList.length
      const tryPick = preferList[idx]
      const leaseKey = tryPick.serverStr
      if (ProxyLease.lease(leaseKey, leaseTtlSec * 1000)) {
        picked = tryPick
        leased = true
        break
      }
    }
    if (!picked)
      picked = pool[Math.floor(Math.random() * pool.length)]

    // 全局旋转模式：per_session 使用粘性会话（对特定供应商启用：ipmars.vip 或用户名包含 -zone-mars）
    let outUsername = picked.username
    const outPassword = picked.password
    try {
      const rotateMode = (config?.proxy as any)?.rotate_mode || 'per_session'
      if (rotateMode === 'per_session') {
        const baseUser = outUsername || ''
        const needSticky = /ipmars\.vip/i.test(picked.serverStr) || /-zone-mars/i.test(baseUser)
        if (needSticky) {
          const minutes = Math.max(1, Math.floor((config?.proxy as any)?.sticky_minutes || 1))
          const sessionId = Math.random().toString(36).slice(2, 10)
          outUsername = `${baseUser}-session-${sessionId}-sessTime-${minutes}`
        }
      }
    }
    catch {}

    return {
      server: picked.serverStr,
      username: outUsername,
      password: outPassword,
      providerId: picked.providerId,
      providerLabel: picked.providerLabel,
      poolSize: totalPoolSize,
      filteredSize: filtered.length,
      candidateSize: candidates.length,
      leased,
    }
  }
  catch {
    return null
  }
}

/**
 * 将代理加入临时黑名单（复用配置更新逻辑）
 */
export async function banProxyForRequest(server: string, reason?: string): Promise<boolean> {
  try {
    const config = getConfig()
    if (!config?.proxy?.enabled)
      return false

    // 动态导入避免循环依赖
    // eslint-disable-next-line ts/no-require-imports
    const { updateConfig } = require('../config/index')
    const ttlMin: number = Math.max(1, Number(config.proxy.blacklist_ttl_minutes || 60))
    const entry = { server, until: Date.now() + ttlMin * 60_000, reason }
    const blacklist = Array.isArray(config.proxy.temp_blacklist) ? config.proxy.temp_blacklist.slice() : []
    blacklist.push(entry)
    await updateConfig({ proxy: { temp_blacklist: blacklist } as any }).catch(() => {})
    return true
  }
  catch {
    return false
  }
}
